package hashUtil;

/**
 * @Author: sun
 * @Description:
 * @Data: create in 15:19 2018/12/17
 * @Modfied by:
 */

//import com.mti1301.GeoHashUtil;

/**
 * BBox，包含2个点，来对应一个矩形的范围，
 * 对应的矩形是以这两个点作为矩形的左下和右上角
 * 所产生的。所以构造方法是传入左下角点和右上角点的横纵坐标，
 * 形如(x1, y1, x2, y2)</p>
 * <b>注意：</b>这个与之前的版本有点不一样，之前的是左上和右下，
 * 现在的是左下和右上角点。(double bottomLeftLon, double bottomLeftLat,
 * double topRightLon, double topRightLat)</p>
 * <pre>
 *     Old        ->    New </p>
 * topLeftLon     |  bottomLeftLon</p>
 * topLeftLat     |  topRightLat</p>
 * bottomRightLon |  topRightLon</p>
 * bottomRightLat |  bottomLeftLat</p>
 * </pre>
 * @author QiuFeng
 *
 */
public class BBox {
    public final double bottomLeftLon;
    public final double bottomLeftLat;
    public final double topRightLon;
    public final double topRightLat;

    private final static double ZERO = 0.0000001;

    public BBox(double bottomLeftLon, double bottomLeftLat, double topRightLon, double topRightLat) {
    	this.bottomLeftLon = bottomLeftLon < topRightLon ? bottomLeftLon : topRightLon;
    	this.bottomLeftLat = bottomLeftLat < topRightLat ? bottomLeftLat : topRightLat;
    	this.topRightLon   = topRightLon > bottomLeftLon ? topRightLon : bottomLeftLon;
    	this.topRightLat   = topRightLat > bottomLeftLat ? topRightLat : bottomLeftLat;
    }

    @Override
    public String toString() {
    	return  bottomLeftLon+" "+bottomLeftLat+" "+topRightLon+" "+topRightLat;
    }

    /**
     * 判断本矩形this是否包含另一个矩形beContain，如果是，返回true，否则返回false。
     * @param beContain
     * @return
     */
    public boolean contain(BBox beContain){
    	return contain(beContain, false);
    }

    /**
     * 判断本矩形this是否包含另一个矩形beContain，如果是，返回true，否则返回false。
     * fuzzy 表示是否启动模糊查询，fuzzy为true时，开启模糊边界查询，即认为当边界相差
     * 小于一个接近于0的值ZERO时，认为这两个边界是重合的。
     * @param beContain
     * @param fuzzy
     * @return true or false.
     */
    public boolean contain(BBox beContain, boolean fuzzy ){
        boolean result = false;
        if(fuzzy){
        	result = (Math.abs(topRightLat - beContain.topRightLat) <= ZERO || topRightLat >= beContain.topRightLat)
        			&& (Math.abs(bottomLeftLon - beContain.bottomLeftLon) <= ZERO || bottomLeftLon <= beContain.bottomLeftLon)
        			&& (Math.abs(bottomLeftLat - beContain.bottomLeftLat) <= ZERO || bottomLeftLat <= beContain.bottomLeftLat)
        			&& (Math.abs(topRightLon - beContain.topRightLon) <= ZERO || topRightLon >= beContain.topRightLon);
        } else {
          result = (topRightLat >= beContain.topRightLat)
        		  && (bottomLeftLon <= beContain.bottomLeftLon)
        		  && (bottomLeftLat <= beContain.bottomLeftLat)
        		  && (topRightLon >= beContain.topRightLon);
          //分别对应上边界，左边界，下边界，右边界 的位置关系
		}
        return result;
    }

    /**
     * 判断本矩形框this是否与beInterset对应的矩形框有交集,有返回true，无返回false
     * @param beInterset
     * @return true or false.
     */
    public boolean interset(BBox beInterset){
    	return interset(beInterset, false);
    }

    /**
     * 判断本矩形框this是否与beInterset对应的矩形框有交集,有返回true，无返回false
     * fuzzy 表示是否启动模糊查询，fuzzy为true时，开启模糊边界查询，即认为当边界相差
     * 小于一个接近于0的值ZERO时，认为这两个边界是重合的。
     * @param beInterset 待判断的矩形框
     * @return true or false.
     */
    public boolean interset(BBox beInterset, boolean fuzzy){
        //相反结果
        boolean oppResult = true;
        //相离更好判断，判断是否相离后取反就是相交的结果，所以包含也是一种特殊情况的相交
        if(fuzzy){
        	oppResult = (topRightLat < beInterset.bottomLeftLat || Math.abs((topRightLat - beInterset.bottomLeftLat)) < ZERO)
        		|| (bottomLeftLat > beInterset.topRightLat || Math.abs((bottomLeftLat - beInterset.topRightLat)) < ZERO)
        		|| (bottomLeftLon > beInterset.topRightLon || Math.abs((bottomLeftLon - beInterset.topRightLon)) < ZERO)
        		|| (topRightLon < beInterset.bottomLeftLon || Math.abs((topRightLon - beInterset.bottomLeftLon)) < ZERO);
        } else {
        	oppResult = (topRightLat < beInterset.bottomLeftLat)
                  || (bottomLeftLat > beInterset.topRightLat)
                  || (bottomLeftLon > beInterset.topRightLon)
                  || (topRightLon < beInterset.bottomLeftLon);
		}
        return !oppResult;
    }
}
